package com.pshare.framework.service;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.pshare.commonid.IdGenerator;
import com.pshare.framework.exception.SeaxRuntimeException;
import com.pshare.framework.exception.TooManyResultsException;
import com.pshare.framework.exception.WrongParamException;
import com.pshare.framework.mapper.BaseMapper;
import com.pshare.framework.page.PageInfo;
import com.pshare.framework.query.QueryInfo;
import com.pshare.tool.SessionTool;
import com.pshare.util.MapUtil;

/**
 * 公用父类Service
 */
@Service
public abstract class BaseService<PK, T> {

	private static final Logger logger = Logger.getLogger(BaseService.class);

	private static final Integer DEFAULT_SHARD_ID = 12345678;
	//private static IdGenerator idGenerator = IdGenerator.getInstance();
	protected abstract BaseMapper<PK, T> getBaseMapper();

	/**
	 * 根据主键id获取对象
	 * 
	 * @param id
	 * @return
	 */
	@Transactional(readOnly = false)
	public T get(PK id) {
		if (id == null) {
			throw new WrongParamException();
		}
		try {
			return getBaseMapper().get(id);
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			throw e;
		}
	}

	@Transactional(readOnly = false)
	public <T> T getVO(PK id, Class<T> c) {
		if (id == null) {
			throw new WrongParamException();
		}
		try {
			return (T) getBaseMapper().getVO(id);
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			throw e;
		}
	}

	/**
	 * 根据条件计算相应的结果集数量
	 * 
	 * @param params
	 * @return int
	 */
	@Transactional(readOnly = false)
	public int queryVOCount(Map<String, Object> params) {
		try {
			return getBaseMapper().queryVOCount(params);
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			throw e;
		}
	}

	@Transactional(readOnly = false)
	public int queryCount(Map<String, Object> params) {
		try {
			return getBaseMapper().queryCount(params);
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			throw e;
		}
	}
	
	@Transactional(readOnly = false)
	public int queryDetailCount(Map<String, Object> params) {
		try {
			return getBaseMapper().queryDetailCount(params);
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			throw e;
		}
	}

	/**
	 * 根据条件查询结果集，适用于分页场景
	 * 
	 * @param queryInfo
	 * @param pageSize
	 * @return PageInfo<T>
	 */
	@Transactional(readOnly = false)
	public PageInfo<T> queryList(QueryInfo queryInfo) {
		PageInfo<T> page = new PageInfo<T>(queryInfo.getPage(), queryInfo.getPageSize());
		Map<String, Object> params = new HashMap<String, Object>();
		MapUtil.populateMap(params, queryInfo);
		if (queryInfo.getParams().size() > 0) {
			params.putAll(queryInfo.getParams());
		}

		List<T> list = null;
		try {
			int count = queryCount(params);
			if (count > 0) {
				page.setTotalCount(count);
				params.put("offset", page.readOffset());
				list = getBaseMapper().queryList(params);
			}
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			throw e;
		}
		if (list == null) {
			list = new ArrayList<T>();
		}

		page.setList(list);
		return page;
	}
	
	/**
	 * 根据条件查询结果集，适用于分页场景
	 * 两表联合查询
	 * @param queryInfo
	 * @param pageSize
	 * @return PageInfo<T>
	 */
	@Transactional(readOnly = false)
	@SuppressWarnings({ "unchecked", "hiding" })
	public <T> PageInfo<T> queryDetailListVO(QueryInfo queryInfo,Class<T> c) {
		PageInfo<T> page = new PageInfo<T>(queryInfo.getPage(), queryInfo.getPageSize());
		Map<String, Object> params = new HashMap<String, Object>();
		MapUtil.populateMap(params, queryInfo);
		if (queryInfo.getParams().size() > 0) {
			params.putAll(queryInfo.getParams());
		}
		List<T> list = null;
		try {
			int count = queryDetailCount(params);
			if (count > 0) {
				page.setTotalCount(count);
				params.put("offset", page.readOffset());
				list = (List<T>)getBaseMapper().queryDetailListVO(params);
			}
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			throw e;
		}
		if (list == null) {
			list = new ArrayList<T>();
		}

		page.setList(list);
		return page;
	}

	/**
	 * 查询返回泛型类型的结果集，并分页(resultMap返回类型要与泛型类型一致)
	 * 
	 * @param queryInfo
	 * @param pageSize
	 * @return PageInfo<T>
	 */
	@Transactional(readOnly = false)
	@SuppressWarnings({ "unchecked", "hiding" })
	public <T> PageInfo<T> queryVOList(QueryInfo queryInfo, Class<T> c) {
		PageInfo<T> page = new PageInfo<T>(queryInfo.getPage(), queryInfo.getPageSize());
		Map<String, Object> params = new HashMap<String, Object>();
		MapUtil.populateMap(params, queryInfo);
		if (queryInfo.getParams().size() > 0) {
			params.putAll(queryInfo.getParams());
		}

		List<T> list = null;
		try {
			int count = this.queryVOCount(params);
			if (count > 0) {
				page.setTotalCount(count);
				params.put("offset", page.readOffset());
				list = (List<T>) this.getBaseMapper().queryVOList(params);
			}
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			throw e;
		}
		if (list == null) {
			list = new ArrayList<T>();
		}

		page.setList(list);
		return page;
	}

	/**
	 * 根据条件查询结果集,适用于无需分页场景
	 * 
	 * @param params
	 * @return List<T>
	 */
	@Transactional(readOnly = false)
	public List<T> query(Map<String, Object> params) {
		try {
			return getBaseMapper().query(params);
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			throw e;
		}
	}

	@Transactional(readOnly = false)
	public List<Long> queryId(Map<String, Object> params) {
		try {
			return getBaseMapper().queryId(params);
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			throw e;
		}
	}

	/**
	 * 根据条件查询结果集,适用于无需分页场景
	 * 
	 * @param queryInfo
	 * @return List<T>
	 */
	@Transactional(readOnly = false)
	public List<T> query(QueryInfo queryInfo) {
		Map<String, Object> params = new HashMap<String, Object>();
		MapUtil.populateMap(params, queryInfo);
		if (queryInfo.getParams().size() > 0) {
			params.putAll(queryInfo.getParams());
		}

		return query(params);
	}

	/**
	 * 根据条件查询结果ID列表
	 * 
	 * @param queryInfo
	 * @return List<Long>
	 */
	@Transactional(readOnly = false)
	public List<Long> queryId(QueryInfo queryInfo) {
		Map<String, Object> params = new HashMap<String, Object>();
		MapUtil.populateMap(params, queryInfo);
		if (queryInfo.getParams().size() > 0) {
			params.putAll(queryInfo.getParams());
		}

		return queryId(params);
	}

	/**
	 * 查询所有结果
	 * 
	 * @return List<T>
	 */
	@Transactional(readOnly = false)
	public List<T> queryAll() {
		return query(new HashMap<String, Object>());
	}

	/**
	 * 查询返回泛型类型的结果集，并分页(resultMap返回类型要与泛型类型一致)
	 * 
	 * @param params 参数
	 * @param c 返回类型
	 * @return
	 */
	@Transactional(readOnly = false)
	@SuppressWarnings({ "hiding", "unchecked" })
	public <T> List<T> queryVO(Map<String, Object> params, Class<T> c) {
		List<T> list = (List<T>) this.getBaseMapper().queryVO(params);
		return list;
	}

	@Transactional(readOnly = false)
	public <T> List<T> queryVO(QueryInfo queryInfo, Class<T> c) {
		PageInfo<T> page = new PageInfo<T>(queryInfo.getPage(), queryInfo.getPageSize());
		Map<String, Object> params = new HashMap<String, Object>();
		MapUtil.populateMap(params, queryInfo);
		if (queryInfo.getParams().size() > 0) {
			params.putAll(queryInfo.getParams());
		}

		return queryVO(params, c);
	}

	/**
	 * 获取唯一结果
	 * 
	 * @param params
	 * @return T
	 */
	@Transactional(readOnly = false)
	public T findOne(Map<String, Object> params) {
		List<T> list = (List<T>) query(params);
		if (list == null || list.size() == 0) {
			return null;
		} else if (list.size() > 1) {
			logger.error("more than 1 result found.");
			throw new TooManyResultsException();
		}
		return list.get(0);
	}

	/**
	 * 获取第一条匹配数据
	 * 
	 * @param params
	 * @return T
	 */
	@Transactional(readOnly = false)
	public T findFirst(Map<String, Object> params) {
		List<T> list = (List<T>) query(params);
		if (list == null || list.size() == 0) {
			return null;
		}
		return list.get(0);
	}
	
	public <T> T findLastVO(Map<String, Object> params, Class<T> c) {
		PageInfo<T> page = new PageInfo<T>(1, 1);
		params.put("orderBySql", "id desc");
		List<T> list = queryVO(params, c);
		if (list != null && list.size() > 0) {
			return list.get(0);
		}
		return null;
	}

	/*private Long generateId(Class clz) {
		return idGenerator.getId(clz.toString(), DEFAULT_SHARD_ID);
	}*/

	/**
	 * 向数据库新增实体对象，并返回生成的ID
	 * 
	 * @param bean
	 * @return Long
	 */
	@Transactional
	public void add(T bean) {
		if (bean == null) {
			throw new WrongParamException();
		}

		//Class clz = bean.getClass();
		/*Long generatedId = generateId(clz);
		try {
			Method[] methods = clz.getMethods();
			for (Method method : methods) {
				String methodName = method.getName();
				if ("setId".equals(methodName)) {
					method.setAccessible(true);
					method.invoke(bean, generatedId);
				} else if ("setCreateBy".equals(methodName)) {
					method.setAccessible(true);
					method.invoke(bean, SessionTool.getUserId());
				}
			}
		} catch (IllegalArgumentException | IllegalAccessException | SecurityException | InvocationTargetException e) {
			logger.error(e.getMessage(), e);
			throw new SeaxRuntimeException();
		}*/

		try {
			getBaseMapper().add(bean);
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			throw new SeaxRuntimeException();
		}
	}

	/**
	 * 修改实体对象
	 * 
	 * @param bean
	 */
	@Transactional
	public void update(T bean) {
		if (bean == null) {
			throw new WrongParamException();
		}
//		Method[] methods = bean.getClass().getMethods();
//		try {
//			for (Method method : methods) {
//				String methodName = method.getName();
//				if ("setUpdateBy".equals(methodName)) {
//					method.setAccessible(true);
//					method.invoke(bean, SessionTool.getUserId());
//				}
//			}
//		} catch (IllegalArgumentException | IllegalAccessException | SecurityException | InvocationTargetException e) {
//			logger.error(e.getMessage(), e);
//			throw new SeaxRuntimeException();
//		}
		try {
			getBaseMapper().update(bean);
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			throw new SeaxRuntimeException();
		}
	}

	/**
	 * 删除实体对象
	 * 
	 * @param params
	 */
	@Transactional
	public void delete(Map<String, Object> params) {
		if (params == null || params.size() == 0) {
			throw new WrongParamException();
		}

		try {
			getBaseMapper().delete(params);
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			throw new SeaxRuntimeException();
		}
	}

	/**
	 * 根据ID删除对象
	 * 
	 * @param id
	 */
	@Transactional
	public void delete(PK id) {
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("id", id);
		try {
			getBaseMapper().delete(params);
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			throw new SeaxRuntimeException();
		}
	}

}
